package com.googlecode.sere.util

import java.util.Enumeration
import java.io.{OutputStream, ByteArrayOutputStream, InputStream}
import java.{ util => ju }

object Implicits {
	implicit def enum2Iterator[A](e: Enumeration[A]) = new Iterator[A] {
		def next = e.nextElement
		def hasNext = e.hasMoreElements
	}
 
	implicit def inputStreamExtras(s: InputStream) = new {
		def slurp() = StreamHelp.slurp(s)
	}

  /**
   * Implicitly converts a Java <code>Iterator</code> to a Scala <code>Iterator</code>.
   * The returned Scala <code>Iterator</code> is backed by the provided Java
   * <code>Iterator</code> and any side-effects of using it via the Scala interface will
   * be visible via the Java interface and vice versa.
   * <p>
   * If the Java <code>Iterator</code> was previously obtained from an implicit or
   * explicit call of <code>asIterator(scala.collection.Iterator)</code> then the original
   * Scala <code>Iterator</code> will be returned.
   *
   * @param i The <code>Iterator</code> to be converted.
   * @return A Scala <code>Iterator</code> view of the argument.
   */
  implicit def asIterator[A](i : ju.Iterator[A]) = i match {
    case IteratorWrapper(wrapped) => wrapped
    case _ => JIteratorWrapper(i)
  }
}

object StreamHelp {
	/** Slurps the entire input stream into a byte array. */
	def slurp(in: InputStream): Array[Byte] = {
		val out = new ByteArrayOutputStream
		pump(in, out)
		out.toByteArray
	}

	/** Pumps all data from the input stream through to the output stream.
	 * Returns the number of bytes transferred. */
	def pump(in: InputStream, out: OutputStream) = {
		val buf = new Array[Byte](65536)
		var count = 0
        var len = in.read(buf)
		while (len > -1) {
			out.write(buf, 0, len)
			count += len
			len = in.read(buf)
		}
		count
	}
}

case class IteratorWrapper[A](underlying : Iterator[A]) extends ju.Iterator[A]
  with ju.Enumeration[A] {
  
  def hasNext = underlying.hasNext
  def next = underlying.next
  def hasMoreElements = underlying.hasNext
  def nextElement = underlying.next
  def remove = throw new UnsupportedOperationException
}

case class JIteratorWrapper[A](underlying : ju.Iterator[A]) extends Iterator[A] {
  def hasNext = underlying.hasNext
  def next = underlying.next
}
